package com.itic.appbase.applications.imports;

import java.io.InputStream;
import java.io.PushbackInputStream;
import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.poi.POIXMLDocument;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.DateUtil;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.itic.appbase.framework.utils.DateHelper;
import com.itic.appbase.framework.utils.ReflectHelper;
import com.itic.appbase.framework.utils.StringHelper;

/**
 * 导入excel表
 * <p>Company: itic</p>
 * @author: shijun
 * @date: 2015年5月8日 上午10:17:40
 * @version: V1.0
 */
public class ImportExcel {
    /** 日志 */ 
    protected  Logger log = LoggerFactory.getLogger(this.getClass());    

    /** 总行数 */        
    private int totalRows = 0;  
  
    /** 总列数 */    
    private int totalCells = 0;  
  
    /** 所有错误信息的list集合 */ 
    private List<ErrorInfo> errorInfoList = new ArrayList<ErrorInfo>();
   
    /** 每行错误信息的list集合 */ 
    private List<ErrorInfo> errorRowInfoList ;
    
    /** 错误信息所在的行集合 */ 
    private List<Integer> errorRowIndexList;
    
    /** 单元格值验证 */  
    private ImportValidatorUtil importValidatorUtil;
    
    /** 获取所有的合并cell */
    private List<CellRangeAddress> cellRangeAddressList;
    
    /** 获取codeDetailService的bean */   
    public ImportExcel(){ 
    } 
    /**
     * 根据流读取Excel文件 
     * @param inputStream  输入流
     * @param classURL     反射类路径
     * @param ignoreError  错误信息
     * @param fields    字段
     * @param types   字段类型
     * @param validators 验证类型
     * @param formats  数据格式化
     * @param startRow  开始行
     * @param startColumn 开始列
     * @param hiddenSheets 隐藏工作表
     * @return Map<String,Object> key值:error:返回错误信息，data：List<?>
     * @throws Exception
     */
    public Map<String,Object> readExcel(InputStream inputStream,String classURL,String ignoreError, String[] fields,String[] types ,String[] validators, String[] formats, int startRow,int startColumn, String[] hiddenSheets) throws Exception  
    {  
          /**获取Workbook*/
          Workbook wb = create(inputStream);
          /**读取数据*/
          Map<String,Object> dataMap = readData(wb,classURL,ignoreError,fields,types,validators,formats,startRow,startColumn,hiddenSheets);
          return dataMap;  
    }
    /**
     * 根据excel版本，调用相应的Workbook，解析excel
     * <p>获取Workbook
     * <p>xls：HSSFWorkbook
     * <p>xlsx：XSSFWorkbook
     * @param inputStream 输入流
     * @return Workbook 工作薄
     * @throws Exception
     */
    public  Workbook create(InputStream inputStream) throws Exception {
        InputStream inputStrema1 = inputStream;
        if (!inputStrema1.markSupported()) {
            inputStrema1 = new PushbackInputStream(inputStrema1, 8);
        }
        if (POIFSFileSystem.hasPOIFSHeader(inputStrema1)) {
            return new HSSFWorkbook(inputStrema1);
        }
        if (POIXMLDocument.hasOOXMLHeader(inputStrema1)) {
            return new XSSFWorkbook(OPCPackage.open(inputStrema1));
        }
        throw new IllegalArgumentException("Excel版本目前poi解析不了");
    }
    /**
     * 解析excel，读取数据
     * @param wb 工作薄
     * @param classURL 反射类路径
     * @param ignoreError 忽略错误
     * @param fields 字段
     * @param types 字段类型
     * @param validators 字段校验
     * @param formats 数据格式化
     * @param startRow 开始行
     * @param startColumn 开始列
     * @param hiddenSheets 工作表
     * @return Map<String,Object> key值:error:返回错误信息，data：List<?>
     * @throws Exception
     */
    @SuppressWarnings({ "unchecked" })
    private  Map<String,Object> readData(Workbook wb,String classURL,String ignoreError, String[] fields,String[] types,String[] validators, String[] formats, int startRow,int startColumn, String[] hiddenSheets) throws Exception  
    {  
        Map<String,Object> dataMap = new HashMap<String, Object>();
        
        /** 获取Excel中每一行的数据 */  
        List<Object> dataLst = null; 

        //获取工作薄的错误信息：工作表的索引和工作表中的错误行的索引
        List<Map<String,Object>> validataTableInfoList = validataTable(wb, fields, validators, startRow, startColumn,hiddenSheets);
        
        List<Integer> sheetList=new ArrayList<Integer>();//保存有错误信息工作表的索引
        List<List<Integer>> sheetRowsList=new ArrayList<List<Integer>>();//保存工作表中错误的行的索引
        
        if(validataTableInfoList!=null&&!validataTableInfoList.isEmpty()){//验证有错误
            if("false".equals(ignoreError)){//不忽略错误信息，则返回错误信息
                dataMap.put("error",errorInfoList);
                return dataMap; 
            }else{//忽略错误信息
                dataMap.put("error",errorInfoList);
                for(Map<String,Object> map:validataTableInfoList){
                    Integer sheetIndex=(Integer) map.get("sheetIndex");//获取错误的工作表的索引
                    List<Integer> sheetRows=(List<Integer>) map.get("sheetRowIndexs");//获取错误工作表下面的所有错误行
                    sheetList.add(sheetIndex);
                    sheetRowsList.add(sheetRows);
                }
                dataLst = objectToList(wb, classURL, fields, types,validators,formats, startRow, startColumn,sheetList,sheetRowsList,hiddenSheets); 
            }
        }else{//没有错误
            dataLst = objectToList(wb, classURL, fields, types,validators,formats, startRow, startColumn,sheetList,sheetRowsList,hiddenSheets); 
        }
        dataMap.put("data", dataLst);
        return dataMap;  
    }
    /**
     * Excel工作表每行数据集合
     * <p>Excel工作表中每行的单元格数据组装为object，然后object在组成list集合
     * @param wb 工作薄
     * @param classURL 反射类路径
     * @param fields 字段
     * @param types 字段类型
     * @param validators 验证
     * @param formats 数据格式化
     * @param startRow 开始行
     * @param startColumn 开始列
     * @param sheetList 工作表
     * @param sheetRowsList 工作表中的行坐标
     * @param hiddenSheets 隐藏工作表
     * @return List<Object>工作表中每行数据集合
     * @throws Exception
     */
    private List<Object> objectToList(Workbook wb, String classURL,String[] fields, String[] types, String[] validators,String[] formats, int startRow, int startColumn, List<Integer> sheetList, List<List<Integer>> sheetRowsList, String[] hiddenSheets)throws Exception{
            
    List<Object> dataLst = new ArrayList<Object>();
    
    for (int numSheet = 0; numSheet < wb.getNumberOfSheets(); numSheet++) {
        
        //循环sheet工作表
        Sheet sheet = wb.getSheetAt(numSheet);
        if(sheet==null){
            continue;
        }
        
        //过滤制定的工作表
        boolean filterFlag=filterSheet(hiddenSheets, sheet.getSheetName());
        if(filterFlag){
            log.info("过滤的工作表是："+sheet.getSheetName());
            continue;
        }
        /** 得到Excel的行数 */  
        this.totalRows = sheet.getPhysicalNumberOfRows(); 
        
        if(sheetList!=null&&!sheetList.isEmpty()){//含有错误信息的工作表sheet
            if(sheetList.contains(numSheet)){//含有错误信息的工作表sheet中是否包含遍历的工作表索引
                for(int m=0;m<sheetList.size();m++){
                    Integer errorSheetIndex=sheetList.get(m);//获取索引号
                    if(errorSheetIndex==numSheet){//如果遍历的工作表索引等于有错误的工作表索引，则判断错误行的索引，若行索引相同，则continue
                        
                        List<Integer> errorRowIndexs = sheetRowsList.get(m);//工作表中有错误信息行的索引
                        
                        List<Integer> rowIndexs=new ArrayList<Integer>();//存放没有错误信息行的索引
                        
                        //遍历工作表中的行，过滤工作表中错误的行
                        for(int b=startRow;b<this.totalRows;b++){
                            if(errorRowIndexs.contains(b)){
                                continue;
                            }else{
                                rowIndexs.add(b);
                            }
                        }
                        
                        /** 循环Excel中没有错误的行，读取数据 */ 
                        for(Integer index:rowIndexs){
                            Row row = sheet.getRow(index);  
                            if (row == null){  
                                continue;  //判断行是否为空，为空则继续循环
                            }  
                            Object object=rowToObject(row, classURL, fields, types, validators,formats, startColumn);
                            dataLst.add(object);
                        }
                        
                    }else{
                        continue;
                    }
                }
           }else{
               /** 循环Excel的行，从指定的行开始读取数据 */ 
               for (int r = startRow; r < this.totalRows; r++)  
               {  
                   Row row = sheet.getRow(r);  
                   if (row == null)  
                   {  
                       continue;  //判断行是否为空，为空则继续循环
                   }  
                   Object object=rowToObject(row, classURL, fields, types, validators,formats, startColumn);
                   
                   dataLst.add(object);//保存第r行数据
               }
           }
        }else{
            /** 循环Excel的行，从指定的行开始读取数据 */ 
            for (int r = startRow; r < this.totalRows; r++)  
            {  
                Row row = sheet.getRow(r);  
                if (row == null)  
                {  
                    continue;  //判断行是否为空，为空则继续循环
                }  
                Object object=rowToObject(row, classURL, fields, types,validators,formats, startColumn);
                
                dataLst.add(object);//保存第r行数据
            }
         }
     }
    return dataLst;
}
    /**
     * 过滤sheet表
     * @param hiddenSheets
     * @param sheetName
     * @return boolean
     *                  过滤返回true,不过滤返回false
     */
    private boolean filterSheet(String[] hiddenSheets,String sheetName){
        boolean filterFlag=false;
        if(hiddenSheets!=null&&hiddenSheets.length>0){
            for (int i = 0; i < hiddenSheets.length; i++) {
                if(sheetName.equalsIgnoreCase(hiddenSheets[i])){
                    return true;
                }
            }
        }
        return filterFlag;
    }
    /**
     * 行转换为对象
     * <p>获取行中的每列数据，组成一个object对象返回
     * @param row          行
     * @param classURL     路径
     * @param fields       字段
     * @param types        类型
     * @param validators   字段校验
     * @param formats   字段数据格式化
     * @param startColumn  开始列
     * @return Object      每行组成的object
     * @throws Exception
     */
    @SuppressWarnings({ "rawtypes" })
    private Object rowToObject(Row row,String classURL,String[] fields, String[] types, String[] validators,String[] formats, int startColumn) throws Exception{
        
        Class clazz = Class.forName(classURL);
        Object object = clazz.newInstance();
            /** 循环Excel的列 */  
            /** 判断字段类型,将转换后的字段数据放到object中 */
            for(int i = 0 ; i < fields.length ; i++) {
               
                /** 获取指定的列读取单元格数据  */ 
                Cell cell = row.getCell(i+startColumn);
                
                if("java.lang.String".equals(types[i])) {
                    String fieldValue=getValue(cell);
                    fieldValue = stringFormat(fields[i], formats,fieldValue);
                    ReflectHelper.setValueByFieldName(object, fields[i], fieldValue);
                }else if("java.lang.Double".equals(types[i])) {
                    BigDecimal bd=numberFormat(fields[i], formats, getValue(cell));
                    if(bd!=null){
                        double doubleVal=bd.doubleValue();
                        ReflectHelper.setValueByFieldName(object, fields[i], doubleVal);
                    }
                    
                }else if("java.lang.Integer".equals(types[i])) {
                    ReflectHelper.setValueByFieldName(object, fields[i], Integer.parseInt(getValue(cell)));
                    
                }else if("java.lang.Boolean".equals(types[i])) {
                    ReflectHelper.setValueByFieldName(object, fields[i], Boolean.parseBoolean(getValue(cell)));
                } else if("java.util.Date".equals(types[i])) {
                    Date date = DateHelper.parseDate(getValue(cell, null));
                    if(date!=null){
                        ReflectHelper.setValueByFieldName(object, fields[i], date);
                    }
                    
                } else if("java.math.BigDecimal".equals(types[i])) {
                    
                    BigDecimal bd=numberFormat(fields[i], formats, getValue(cell));
                    if(bd!=null){
                        ReflectHelper.setValueByFieldName(object, fields[i], bd);
                    }
                    
                } else if("java.lang.Float".equals(types[i])) {
                    BigDecimal bd=numberFormat(fields[i], formats, getValue(cell));
                    if(bd!=null){
                        float floatVal=bd.floatValue();
                        ReflectHelper.setValueByFieldName(object, fields[i], floatVal);
                    }
                } else if("java.lang.Short".equals(types[i])) {
                    String value = getValue(cell);
                    if (!StringHelper.isBlank(value)){
                        value = value.contains(".")? value.substring(0,value.lastIndexOf(".")):value;
                        ReflectHelper.setValueByFieldName(object, fields[i], Short.parseShort(value));
                    } 
                } else {
                    ReflectHelper.setValueByFieldName(object, fields[i], new Object[]{});
                }
            }
            return object;
    }
    /**
     * 字符串空值转换
     * @param field 字段
     * @param formats 字段数据格式化
     * @param fieldValue 单元格值
     * @return String 返回转换值
     */
    private String stringFormat(String field,String[] formats,String fieldValue){
        String stringFormat=null;
        try {
            if(formats.length>0){//格式化类型数组不为空
                for (int i = 0; i < formats.length; i++) {//遍历每个数组
                    //获取验证规则
                    String[] formatsString=formats[i].split(",");//获取所有的验证 
                    int length=formatsString.length;//判断字段的长度
                    if(length>0){
                        String[] fields=formatsString[0].split(":");//获得需要格式化的字段bigNum
                        if("field".equals(fields[0])){
                            if(field.equalsIgnoreCase(fields[1])){//字段相同
                                if(length==3){
                                    String[] blanks=formatsString[2].split(":");//获得需要格式化的字段
                                    //判断单元格的值是否为空，为空则指定单元格的值为设定的值即blanks[1]
                                    if("blank".equals(blanks[0])){
                                        if(StringHelper.isBlank(fieldValue)){
                                            if(StringHelper.isBlank(blanks[1])){//字段为空，并且替换字段也为空，则返回空值
                                                return stringFormat;
                                            }
                                            fieldValue=blanks[1];
                                        }
                                    }
                                }else{
                                    String[] unKnow=formatsString[1].split(":");//未知类型
                                    if("blank".equals(unKnow[0])){
                                        if(StringHelper.isBlank(fieldValue)){
                                            if(StringHelper.isBlank(unKnow[1])){//字段为空，并且替换字段也为空，则返回空值
                                                return stringFormat;
                                            }
                                            fieldValue=unKnow[1];
                                        }
                                    }
                                }
                         }
                     }
                 }
              }
            }
        } catch (Exception e) {
            log.info("单元格字符串转换失败："+e.getMessage());
            throw new RuntimeException(e);
        }
        return fieldValue;
    }
    
    /**
     * 数字精度转换
     * @param field 字段
     * @param formats 字段数据格式化
     * @param fieldValue 单元格值
     * @return BigDecimal转换值
     * @throws Exception
     */
    private  BigDecimal numberFormat(String field,String[] formats,String fieldValue) throws Exception{
        BigDecimal bd=null;
        try {
            if(formats.length>0){//格式化类型数组不为空
                for (int i = 0; i < formats.length; i++) {//遍历每个数组
                    //获取验证规则
                    String[] formatsString=formats[i].split(",");//获取所有的验证 
                    int length=formatsString.length;//判断字段的长度
                    if(length>0){
                        String[] fields=formatsString[0].split(":");//获得需要格式化的字段bigNum
                        if("field".equals(fields[0])){
                            if(field.equalsIgnoreCase(fields[1])){//字段相同
                                if(length==3){
                                    String[] fmts=formatsString[1].split(":");//获得需要格式化
                                    String[] blanks=formatsString[2].split(":");//获得需要格式化的字段
                                    //判断单元格的值是否为空，为空则指定单元格的值为设定的值即blanks[1]
                                    if("blank".equals(blanks[0])){
                                        if(StringHelper.isBlank(fieldValue)){
                                            if(StringHelper.isBlank(blanks[1])){//字段为空，并且替换字段也为空，则返回空值
                                                return bd;
                                            }
                                            fieldValue=blanks[1];
                                        }
                                    }
                                    bd=setBigDecimalDigit(fieldValue, fmts[1]);
                                }else{
                                    String[] unKnow=formatsString[1].split(":");//未知类型
                                    if("blank".equals(unKnow[0])){
                                        
                                        if(StringHelper.isBlank(fieldValue)){
                                            if(StringHelper.isBlank(unKnow[1])){//字段为空，并且替换字段也为空，则返回空值
                                                return bd;
                                            }
                                            fieldValue=unKnow[1];
                                        }
                                        bd=new BigDecimal(fieldValue);
                                    }else if("fmt".equals(unKnow[0])){
                                        if(StringHelper.isBlank(fieldValue)){
                                            return null;
                                        }
                                        bd=setBigDecimalDigit(fieldValue, unKnow[1]);
                                    }else{
                                        log.info("格式化参数设置错误");
                                        throw new Exception("格式化参数设置错误");
                                    }
                                }
                         }
                     }
                 }
              }
          }else{//格式化数组为空
                   bd=new BigDecimal(fieldValue);
          }
        } catch (Exception e) {
            log.info("数字转换失败："+e.getMessage());
            throw new RuntimeException(e);
        }
        return bd;
    }
    
    /**
     * 单元格数据
     * @param cell 单元格
     * @return String 单元格数据
     * @throws Exception
     */
    private  String getValue(Cell cell) throws Exception{
        /**字段必填项、格式校验**/
        return getCellValue(cell);
    }

    /**
     * 实体类中字段为Date时格式化得到Excel表中的值
     * @param cell 单元格
     * @param formatter 字段数据格式化
     * @return 单元格值
     * @throws Exception
     */
    @SuppressWarnings("static-access")
    private  String getValue(Cell cell, String formatter) throws Exception {
        String newFormatter = formatter;
        if(StringHelper.isBlank(newFormatter)){
            newFormatter = "yyyy-MM-dd HH:mm:ss";
        }
        if (cell.getCellType() == cell.CELL_TYPE_BOOLEAN) {
            // 返回布尔类型的值
            return String.valueOf(cell.getBooleanCellValue());
        } else if (cell.getCellType() == cell.CELL_TYPE_NUMERIC) {
            if(DateUtil.isCellDateFormatted(cell)) {
                Date dt = DateUtil.getJavaDate(cell.getNumericCellValue()); 
                return  DateHelper.formatDate(dt, newFormatter);
            }else{
                cell.setCellType(Cell.CELL_TYPE_STRING);
                return cell.getStringCellValue(); 
            }
        } else {
            // 返回字符串类型的值
            String cellValue = cell.getStringCellValue();  //excel中的值
            if (StringHelper.isNotBlank(cellValue)) {
                Date date = DateHelper.parseDate(cellValue);
                if(date!=null){
                    return DateHelper.formatDate(date, newFormatter);
                }
            }
            return null;
        }
    }
    /**
     * 验证表格数据返回错误信息集合
     * @param wb           工作薄对象
     * @param fields       字段数组
     * @param validators   字段的验证类型数组
     * @param startRow     开始行
     * @param startColumn  开始列
     * @param hiddenSheets 隐藏工作表
     * @return List<Map<String,Object>> 
     *                   key1:sheetIndex:记录出现错误的sheet
     *                   key2:sheetRowIndexs:记录sheet中出现问题的行
     */
    private List<Map<String,Object>> validataTable(Workbook wb,String[] fields,String[] validators,int startRow,int startColumn, String[] hiddenSheets){
        
        List<Map<String,Object>> dataErrorLists=new ArrayList<Map<String,Object>>();
        
        for (int numSheet = 0; numSheet < wb.getNumberOfSheets(); numSheet++) {
            
            //循环sheet工作表
            Sheet sheet = wb.getSheetAt(numSheet);
            if(sheet==null){
                continue;
            }
            //获取sheet中所有合并的cell
            getCombineCell(sheet);
            
            boolean filterFlag=filterSheet(hiddenSheets, sheet.getSheetName());
            if(filterFlag){
                log.info("过滤的工作表是："+sheet.getSheetName());
                continue;
            }
            /** 得到Excel的行数 */  
      
            this.totalRows = sheet.getPhysicalNumberOfRows();  
            
            //记录那个sheet 的多少行出现什么问题
            Map<String,Object> validataMap = new HashMap<String, Object>();
            
            //错误行list初始化
            errorRowIndexList=new ArrayList<Integer>();//记录sheet中的错误所在的行
            
            /** 循环Excel的行，从指定的行开始读取数据 */ 
            for (int r = startRow; r < this.totalRows; r++)  
            {  
                   Row row = sheet.getRow(r);  
      
                   if (row == null){  
                        continue;  //判断行是否为空，为空则继续循环
                   } 
                   //每行的错误列list初始化
                   errorRowInfoList = new ArrayList<ErrorInfo>();
                   
                   /** 循环Excel的列 */  
                   for(int i = 0 ; i < fields.length ; i++) {
                         isCombineCell(cellRangeAddressList, row,i+startColumn, sheet);
                         /** 获取指定的列读取单元格数据  */ 
                         String sheetName = sheet.getSheetName();//工作表名称
                         
                         validateVal(sheetName,row,i+startColumn,validators[i]);//单元格验证
                   }
                   if(errorRowInfoList!=null&&!errorRowInfoList.isEmpty()){//判断行中是否出现错误，若出现错误记录相应的错误
                       //这个里面可以在获取每行的错误信息，并把数据每行错误信息和列索引封装为一个map集合
                       errorRowIndexList.add(r);//错误的行组成list集合
                   }
             }
            //判断是行是否有错误信息，有，则将错误信息所在的sheet、行以及错误信息放到validataMap中，并将validataMap放到list中
            if(errorRowIndexList!=null&&!errorRowIndexList.isEmpty()){//若存在错误，则记录是哪个sheet出现错误
                validataMap.put("sheetIndex", numSheet);//记录出现错误的sheet
                validataMap.put("sheetRowIndexs", errorRowIndexList);//记录sheet中出现问题的行
                dataErrorLists.add(validataMap);
            }
          }
        
            return dataErrorLists; 
    }
    /**
     * 单元格值验证
     * @param sheetName   工作表名称
     * @param row         行
     * @param cellnum     列索引
     * @param validators  验证
     * @return void
     */
    @SuppressWarnings("static-access")
    private void validateVal(String sheetName,Row row,int cellnum, String validators){
        getImportValidatorUtil();//验证
        
        Cell cell = row.getCell(cellnum);//获取单元格
        String cellValue=getCellValue(cell);//根据cell的字符类型，获取cell的值
        int rowNum = row.getRowNum();//行坐标
        
        if("error".equalsIgnoreCase(cellValue)){
            addErrorInfoToList(sheetName,rowNum,cellnum,"数据不合法","000");
            log.info("EXCEL表导入异常，工作表"+sheetName+"的第"+(rowNum)+"行，第"+(cellnum)+"列数据不合法");
        }else{
            //获取验证规则
            String[] validatorsString=validators.split(",");//获取所有的验证
            if(validatorsString.length>0){//有验证
                for(int i=0;i<validatorsString.length;i++){//result>>>required:true|lengthLimit:400|chsNoSymbol:true
                    String validator=validatorsString[i];//result>>>required:true
                    String[] validesString = validator.split(":");//获取具体的验证规则
                    if(validesString.length>0){//result>>>required，true
                        /**必填项验证*/
                        if("required".equalsIgnoreCase(validesString[0])){//result>>>required
                            if("true".equalsIgnoreCase(validesString[1])){//result>>>true(必填项验证)
                                boolean requiredFlag=importValidatorUtil.required(cellValue);
                                if(!requiredFlag){//必填项验证通过
                                    addErrorInfoToList(sheetName,rowNum,cellnum,"必填项不能为空","001");

                                    log.info("EXCEL表导入异常，工作表"+sheetName+"的第"+(rowNum)+"行，第"+(cellnum)+"列为必填项不能为空");
                                    break;
                                }
                            }
                        }else if("lengthLimit".equalsIgnoreCase(validesString[0])){/**长度验证*/
                            if(StringHelper.isBlank(cellValue)){
                                
                            }else{
                                boolean requiredFlag=importValidatorUtil.lengthLimit(cellValue,Integer.parseInt(validesString[1]));
                                if(!requiredFlag){//字符长度验证通过
                                    addErrorInfoToList(sheetName,rowNum,cellnum,"长度不能大于"+validesString[1],"002");
                                    log.info("EXCEL表导入异常，工作表"+sheetName+"的第"+(rowNum)+"行，第"+(cellnum)+"列的长度不能大于"+validesString[1]);
                                }
                            }
                        }else if("number".equalsIgnoreCase(validesString[0])){/**数字验证*/
                            if(StringHelper.isBlank(cellValue)){
                                
                            }else{
                                if("true".equalsIgnoreCase(validesString[1])){
                                    boolean requiredFlag=importValidatorUtil.number(cellValue);
                                    if(!requiredFlag){//验证通过
                                        addErrorInfoToList(sheetName,rowNum,cellnum,"必须为数字","003");
                                        log.info("EXCEL表导入异常，工作表"+sheetName+"的第"+(rowNum)+"行，第"+(cellnum)+"列需要为数字");
                                    }
                                }
                            }
                        }else if("email".equalsIgnoreCase(validesString[0])){/**邮箱验证*/
                            if(StringHelper.isBlank(cellValue)){
                                
                            }else{
                                if("true".equalsIgnoreCase(validesString[1])){
                                    boolean requiredFlag=importValidatorUtil.email(cellValue);
                                    if(!requiredFlag){//验证通过
                                        
                                        addErrorInfoToList(sheetName,rowNum,cellnum,"邮箱不符合要求","004");
                                        
                                        log.info("EXCEL表导入异常，工作表"+sheetName+"的第"+(rowNum)+"行，第"+(cellnum)+"列邮箱不符合要求");
                                    }
                                }
                            }
                        }else if("phone".equalsIgnoreCase(validesString[0])){/**电话验证*/
                            if(StringHelper.isBlank(cellValue)){
                                
                            }else{
                                if("true".equalsIgnoreCase(validesString[1])){
                                    boolean requiredFlag=importValidatorUtil.phone(cellValue);
                                    if(!requiredFlag){//验证通过
                                        addErrorInfoToList(sheetName,rowNum,cellnum,"电话不符合要求","005");
                                        
                                        log.info("EXCEL表导入异常，工作表"+sheetName+"的第"+(rowNum)+"行，第"+(cellnum)+"列电话不符合要求");
                                    }
                                }
                            }
                        }else if("mobile".equalsIgnoreCase(validesString[0])){/**手机号验证*/
                            if(StringHelper.isBlank(cellValue)){
                                
                            }else{
                                if("true".equalsIgnoreCase(validesString[1])){
                                    boolean requiredFlag=importValidatorUtil.mobile(cellValue);
                                    if(!requiredFlag){//验证通过
                                        addErrorInfoToList(sheetName,rowNum,cellnum,"手机号不符合要求","006");
    
                                        log.info("EXCEL表导入异常，工作表"+sheetName+"的第"+(rowNum)+"行，第"+(cellnum)+"列手机号不符合要求");
                                    }
                                } 
                            }
                        }else if("tel".equalsIgnoreCase(validesString[0])){/**电话/手机号验证*/
                            if(StringHelper.isBlank(cellValue)){
                                
                            }else{
                                if("true".equalsIgnoreCase(validesString[1])){
                                    boolean requiredFlag=importValidatorUtil.tel(cellValue);
                                    if(!requiredFlag){//验证通过
                                        addErrorInfoToList(sheetName,rowNum,cellnum,"电话/手机号不符合要求","007");
                                        
                                        log.info("EXCEL表导入异常，第"+(rowNum)+"行，第"+(cellnum)+"列电话/手机号不符合要求");
                                    }
                                }
                            }
                        }else if("url".equalsIgnoreCase(validesString[0])){/**url验证*/
                            if(StringHelper.isBlank(cellValue)){
                                
                            }else{
                                if("true".equalsIgnoreCase(validesString[1])){
                                    boolean requiredFlag=importValidatorUtil.url(cellValue);
                                    if(!requiredFlag){//验证通过
                                        addErrorInfoToList(sheetName,rowNum,cellnum,"URL不符合要求","008");

                                        log.info("EXCEL表导入异常，第"+(rowNum)+"行，第"+(cellnum)+"列URL不符合要求");
                                    }
                                }
                            }
                        }else if("zip".equalsIgnoreCase(validesString[0])){/**邮编验证*/
                            if(StringHelper.isBlank(cellValue)){
                                
                            }else{
                                if("true".equalsIgnoreCase(validesString[1])){
                                    boolean requiredFlag=importValidatorUtil.zip(cellValue);
                                    if(!requiredFlag){//验证通过
                                        addErrorInfoToList(sheetName,rowNum,cellnum,"邮编不符合要求","009");

                                        log.info("EXCEL表导入异常，工作表"+sheetName+"的第"+(rowNum)+"行，第"+(cellnum)+"列邮编不符合要求");
                                    }
                                }
                            }
                        }else if("chsNoSymbol".equalsIgnoreCase(validesString[0])){/**中文验证*/
                            if(StringHelper.isBlank(cellValue)){
                                
                            }else{
                                if("true".equalsIgnoreCase(validesString[1])){
                                    boolean requiredFlag=importValidatorUtil.chsNoSymbol(cellValue);
                                    if(!requiredFlag){//验证通过
                                        addErrorInfoToList(sheetName,rowNum,cellnum,"必须为中文","010");
                                        log.info("EXCEL表导入异常，工作表"+sheetName+"的第"+(rowNum)+"行，第"+(cellnum)+"列需要为中文");
                                    }
                                }
                            }
                        }else if("date".equalsIgnoreCase(validesString[0])){/**日期校验*/
                            if(StringHelper.isNotBlank(cellValue)){
                                try {
                                    if(null==DateHelper.parseDate(cellValue)){//转换日期，判断日期是否符合要求
                                        addErrorInfoToList(sheetName,rowNum,cellnum,"日期不符合要求","011");
                                        log.info("EXCEL表导入异常，工作表"+sheetName+"的第"+(rowNum)+"行，第"+(cellnum)+"列日期不符合要求");
                                    };
                                }catch (Exception e) {
                                     addErrorInfoToList(sheetName,rowNum,cellnum,"日期不符合要求","011");
                                     log.info("EXCEL表导入异常，工作表"+sheetName+"的第"+(rowNum)+"行，第"+(cellnum)+"列日期不符合要求");
                                }
                            }
                        } else if ("idCard".equalsIgnoreCase(validesString[0])) {
                            /** 身份证验证 */
                            if (StringHelper.isBlank(cellValue)) {

                            } else {
                                if ("true".equalsIgnoreCase(validesString[1])) {
                                    boolean requiredFlag = importValidatorUtil.idCard(cellValue);
                                    if (!requiredFlag) {// 验证通过
                                        addErrorInfoToList(sheetName, rowNum, cellnum, "身份证不符合", "012");
                                        log.info("EXCEL表导入异常，工作表" + sheetName + "的第" + (rowNum) + "行，第" + (cellnum)
                                                + "列身份证号码不合法");
                                    }
                                }
                            }
                        }else if ("numberDigitHashZero".equalsIgnoreCase(validesString[0])) {
                            /** 小数验证 */
                            if (StringHelper.isBlank(cellValue)) {

                            } else {
                                boolean requiredFlag = importValidatorUtil.numberDigitHashZero(cellValue,Integer.parseInt(validesString[1]),Integer.parseInt(validesString[2]));
                                if (!requiredFlag) {// 验证通过
                                    addErrorInfoToList(sheetName, rowNum, cellnum, "正整数\\小数不符合", "012");
                                    log.info("EXCEL表导入异常，工作表" + sheetName + "的第" + (rowNum) + "行，第" + (cellnum)
                                            + "小数验证不合法");
                                }
                            }
                        } else if ("numberDigitWithMax".equalsIgnoreCase(validesString[0])) {
                            /** 小数验证 */
                            if (StringHelper.isBlank(cellValue)) {

                            } else {
                                boolean requiredFlag = importValidatorUtil.numberDigitWithMax(cellValue,Integer.parseInt(validesString[1]),Integer.parseInt(validesString[2]));
                                if (!requiredFlag) {// 验证通过
                                    addErrorInfoToList(sheetName, rowNum, cellnum, "小数不符合", "012");
                                    log.info("EXCEL表导入异常，工作表" + sheetName + "的第" + (rowNum) + "行，第" + (cellnum)
                                            + "小数验证不合法");
                                }
                            }
                        }else if ("positiveNumber".equalsIgnoreCase(validesString[0])) {
                            /** 正整数验证 含0*/
                            if (StringHelper.isBlank(cellValue)) {

                            } else {
                                if ("true".equalsIgnoreCase(validesString[1])) {
                                    boolean requiredFlag = importValidatorUtil.positiveNumber(cellValue);
                                    if (!requiredFlag) {// 验证通过
                                        addErrorInfoToList(sheetName, rowNum, cellnum, "正整数不符合", "012");
                                        log.info("EXCEL表导入异常，工作表" + sheetName + "的第" + (rowNum) + "行，第" + (cellnum)
                                                + "正整数不合法");
                                    }
                                }
                            }
                        } else if ("beforeYear".equalsIgnoreCase(validesString[0])) {
                            /** 年份验证 不能大于今年，4位数字*/
                            if (StringHelper.isBlank(cellValue)) {

                            } else {
                                if ("true".equalsIgnoreCase(validesString[1])) {
                                    boolean requiredFlag = importValidatorUtil.beforeYear(cellValue);
                                    if (!requiredFlag) {// 验证通过
                                        addErrorInfoToList(sheetName, rowNum, cellnum, "年份不符合", "012");
                                        log.info("EXCEL表导入异常，工作表" + sheetName + "的第" + (rowNum) + "行，第" + (cellnum)
                                                + "年份数据不合法");
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
    
    
    /**
     * 添加错误信息到list
     * @param sheetName      工作表名
     * @param rowIndex       行索引
     * @param columnIndex    列索引
     * @param errorMessage   错误信息
     * @return void
     */
    private void addErrorInfoToList(String sheetName,int rowIndex,int columnIndex,String errorMessage,String errorCode){
        ErrorInfo errorInfo=new ErrorInfo();
        errorInfo.setSheetName(sheetName);
        errorInfo.setRowNum(rowIndex);
        errorInfo.setColumnNum(columnIndex);
        errorInfo.setErrorMessage(errorMessage);
        errorInfo.setErrorCode(errorCode);
        errorInfoList.add(errorInfo);//记录所有的错误
        errorRowInfoList.add(errorInfo);//记录每一行的错误信息
    }
    /**
     * 单例
     * @return
     * @return ImportValidatorUtil
     */
    private ImportValidatorUtil getImportValidatorUtil(){
        if(importValidatorUtil==null){
            importValidatorUtil=new ImportValidatorUtil();
        }
        return importValidatorUtil;
    }
    /**
     * 获取单元格数据
     * <p>根据cell的字符类型，获取cell的值
     * @param cell
     * @return String
     */
    private String getCellValue(Cell cell) {
        String cellValue = "";  
  
        if (null != cell)  
        {  
            // 以下是判断数据的类型  
            switch (cell.getCellType())  
            {  
            case Cell.CELL_TYPE_NUMERIC: // 数字
                if(DateUtil.isCellDateFormatted(cell)) {
                    Date dt = DateUtil.getJavaDate(cell.getNumericCellValue()); 
                    cellValue = DateHelper.formatDateTime(dt);
                }else{
                    //设置单元格格式类型为string类型
                    cell.setCellType(Cell.CELL_TYPE_STRING);
                    cellValue = String.valueOf(cell.getStringCellValue()); 
               } 
                break;  
  
            case Cell.CELL_TYPE_STRING: // 字符串  
                cellValue = cell.getStringCellValue();  
                break;  
  
            case Cell.CELL_TYPE_BOOLEAN: // Boolean  
                cellValue =String.valueOf(cell.getBooleanCellValue());  
                break;  
  
            case Cell.CELL_TYPE_FORMULA: // 公式  
                try {  
                         cellValue = String.valueOf(cell.getStringCellValue());  
                     } catch (IllegalStateException e) {  
                         cellValue = String.valueOf(cell.getNumericCellValue());  
                     }
                break;  
  
            case Cell.CELL_TYPE_BLANK: // 空值  
                cellValue = "";  
                break;  
  
            case Cell.CELL_TYPE_ERROR: // 故障  
                cellValue = "error";  
                break;  
            default:  
                cellValue = "error";  
                break;  
            }  
        }
        return cellValue;
    } 
    
    /**
     * 设置BigDecimal的小数点后保留几位
     * @param numString    传过来的参数
     * @param digitNum     小数点后保留的位数
     * @return BigDecimal  返回处理后的参数
     */
    private static BigDecimal setBigDecimalDigit(String numString,String digitNum){
        
        Double doubleNum=0.0;
        if(!StringHelper.isBlank(numString)){
            doubleNum=Double.parseDouble(numString);
        }
        
        StringBuffer pattern=new StringBuffer("");
        if(!StringHelper.isBlank(digitNum)&&!"0".equals(digitNum)){//保留位数不为空且保留位数不为0
            pattern.append(".");
            int num=Integer.parseInt(digitNum);
            for(int i=0;i<num;i++){
                pattern.append("0");
            }
        }else if(StringHelper.isBlank(digitNum)||"0".equals(digitNum)){//保留位数为空或者小数点后保留0位
            pattern.append("0");
        }
        DecimalFormat df = new DecimalFormat(pattern.toString()); // 保留几位小数
        BigDecimal bd = new BigDecimal(df.format(doubleNum)); // 再将String 转换成 BigDecimal
        return bd;
    }
    
    /**
     * 查找工作表中所有合并的单元格
     * @param sheet
     * @return List<CellRangeAddress> 工作表中合并的单元格
     */
     public List<CellRangeAddress> getCombineCell(Sheet sheet) {
         cellRangeAddressList = new ArrayList<CellRangeAddress>();
         // 获得一个 sheet 中合并单元格的数量
         int sheetmergerCount = sheet.getNumMergedRegions();
         // 遍历合并单元格
         for (int i = 0; i < sheetmergerCount; i++) {
             // 获得合并单元格加入list中
             CellRangeAddress ca = sheet.getMergedRegion(i);
             cellRangeAddressList.add(ca);
         }
         return cellRangeAddressList;
     }

     /**
      * 拆分合并的单元格
      * <p>判断单元格是否为合并单元格,true则拆分单元格，并统一赋值
      * @param listCombineCell      合并的单元格
      * @param rowIndex             行坐标
      * @param colIndex             列坐标
      * @param sheet                工作表
      * @return void
      */
     public void isCombineCell(List<CellRangeAddress> listCombineCell,
             Row row,int colIndex, Sheet sheet) {
        int rowIndex = row.getRowNum();
        boolean isCombineCellFlag = false;
        int index = 0; 
        int firstC = 0;
        int lastC = 0;
        int firstR = 0;
        int lastR = 0;
        for (int i = 0; i < listCombineCell.size(); i++) {
            CellRangeAddress ca = listCombineCell.get(i);
            // 获得合并单元格的起始行, 结束行, 起始列, 结束列
            firstC = ca.getFirstColumn();
            lastC = ca.getLastColumn();
            firstR = ca.getFirstRow();
            lastR = ca.getLastRow();
            if (colIndex <= lastC && colIndex >= firstC) {
                if (rowIndex <= lastR && rowIndex >= firstR) {
                    isCombineCellFlag = true;
                    index = i;
                    break;
                }
            }
        }
        if ( isCombineCellFlag ){
            Cell cell = row.getCell(colIndex);
            String cellValue=getCellValue(cell).trim();//根据cell的字符类型，获取cell的值
            sheet.removeMergedRegion(index);
            
            for(int r =firstR; r<= lastR ;r++ ){
                //获取行
                Row rows=sheet.getRow(r);
                if(rows==null){
                    rows=sheet.createRow(r);
                }
                //获取列
                for(int c =firstC; c<= lastC ;c++ ){
                    Cell cells=rows.getCell(c);
                    if(cells==null){
                        cells = rows.createCell(c);
                    }
                    cells.setCellValue(cellValue);
                }
            }
        }
    }
    //set-get方法
    public List<ErrorInfo> getErrorInfoList() {
        return errorInfoList;
    }

    public void setErrorInfoList(List<ErrorInfo> errorInfoList) {
        this.errorInfoList = errorInfoList;
    }
    
    /**
     * 工作表总行数
     * @return int
     */
    public int getTotalRows(){  
        return totalRows;    
    }  
   
    /**
     * 工作表总列数 
     * @return
     */
    public int getTotalCells(){   
        return totalCells;    
    }  
}
